#include "mcp2515.h"
#include <android/log.h>
#define LOG_TAG  "C_TAG"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
MCP2515::MCP2515():
        isSpiDeviceOpened(false),
        spi("/dev/spidev0.0", 5000000),
        bSpiReceiveDataFlag(false)
{
}

int MCP2515::Init(void)
{
    isSpiDeviceOpened = false;

    if(spi.Init() < 0)
    {
        printf("Spi init error!\n");
        return -1;
    }

    printf("start!!\n");

    unsigned char temp=0;
    spi.WriteOneByte(CAN_RESET);
    sleep(1);

    spi.WriteByte(CANCTRL,REQOP_CONFIG);//enter config mode
    /// sleep(2);
    spi.WriteByte(CNF1,CAN_500Kbps);    //0x00      spi.WriteByte(CNF1,CAN_500Kbps);  spi.WriteByte(0xaa, 0x01);
    ///sleep(2);

    u_int8_t readByte = spi.ReadByte(CNF1);

    if(readByte != CAN_500Kbps)
    {
//        LOGD("error!!  1");
        /// sleep(2);
        return -2;
    }

    spi.WriteByte(CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ); //0x90

    u_int8_t spiR = spi.ReadByte(CNF2);
    u_int8_t un   =  (0x80|PHSEG1_3TQ|PRSEG_1TQ);
    if(spiR != un)
    {
        printf("error!!  2");
        return -3;
    }

    spi.WriteByte(CNF3,PHSEG2_3TQ);    //0x02
    if(spi.ReadByte(CNF3) != (PHSEG2_3TQ))
    {
        printf("error!!  3");
        return -4;
    }

    spi.WriteByte(TXB0SIDH,0xFF);
    if(spi.ReadByte(TXB0SIDH) != (0xFF))
    {
        printf("error!!  4");
//        return -1;
    }

    spi.WriteByte(TXB0SIDL,0xE0);
    if(spi.ReadByte(TXB0SIDL) != (0xE0))
    {
        printf("error!!  5");
//        return -1;
    }

    spi.WriteByte(RXB0SIDH,0x00);
    if(spi.ReadByte(RXB0SIDH) != (0x00))
    {
        printf("error!!  6");
//        return -1;
    }
    spi.WriteByte(RXB0SIDL,0x00);
    if(spi.ReadByte(RXB0SIDL) != (0x00))
    {
        printf("error!!   7");
//        return -1;
    }

    spi.WriteByte(RXB0CTRL,RXM_RCV_ALL | BUKT);
    if(spi.ReadByte(RXB0CTRL) != (RXM_RCV_ALL | BUKT))
    {
        printf("error!!   8");
//        return -1;
    }

    spi.WriteByte(RXB0DLC,DLC_8);
    if(spi.ReadByte(RXB0DLC) != (DLC_8))
    {
        printf("error!!   9");
    }

    spi.WriteByte(RXF0SIDH,0xFF);
    if(spi.ReadByte(RXF0SIDH) != (0xFF))
    {
        printf("error!!  10");
        return -5;
    }


    spi.WriteByte(RXF0SIDL,0xE0);
    int result =  spi.ReadByte(RXF0SIDL);
//     LOGD("result = %d ", result);
    if(spi.ReadByte(RXF0SIDL) != (0xE0))
    {
        printf("error!!  11");
        return -6;
    }



    spi.WriteByte(RXM0SIDH,0xFF);
    if(spi.ReadByte(RXM0SIDH) != (0xFF))
    {
        printf("error!!  12");
        return -7;
    }

    spi.WriteByte(RXM0SIDL,0xE0);
    if(spi.ReadByte(RXM0SIDL) != (0xE0))
    {
        printf("error!!  13");
        return -8;
    }

    spi.WriteByte(CANINTF,0x00);
    if(spi.ReadByte(CANINTF) != (0x00))
    {
        printf("error!!  14");
        return -9;
    }
    spi.WriteByte(CANINTE,0x03);
    if(spi.ReadByte(CANINTE) != (0x03))
    {
        printf("error!!  15");
        return -10;
    }

    spi.WriteByte(CANCTRL,REQOP_NORMAL|CLKOUT_ENABLED|OSM_ENABLED);
    if(spi.ReadByte(CANCTRL) != (REQOP_NORMAL|CLKOUT_ENABLED|OSM_ENABLED))
    {
        printf("error!!   16");
        return -11;
    }

    spi.WriteByte(TXRTSCTRL, 0x04);

    temp=spi.ReadByte(CANSTAT);
    printf("state:0x%2x", temp);
    if(OPMODE_NORMAL!=(temp&&0xE0))
    {
        spi.WriteByte(CANCTRL,REQOP_NORMAL|CLKOUT_ENABLED|OSM_ENABLED);
    }
    isSpiDeviceOpened = true;
    printf("spi init succeed!!\n");
//    LOGD("spi init succeed!!\n");
    return 1;
}

int MCP2515::SendCanData(const CanDataType &data)
{
    unsigned char dly;
    uint16_t cmdWord;

    dly=0;
    while((spi.ReadByte(TXB0CTRL)&0x08) && (dly<50))
    {
        usleep(1000);
        dly++;
    }

    if(dly >= 50)
    {
//        LOGD("dly  = -1");
        return -1;
    }

    cmdWord = data.cmdWord;

    if(!data.dir)
    {
        cmdWord = cmdWord | 0x8000;
    }

    uint8_t buf[data.length + 5 + 4];
    buf[0] = data.id >> 3; //TXDnSIDH
    buf[1] = (data.id << 5) & 0xE0; //TXDnSIDL
    buf[2] = 0;//TXDnEID8
    buf[3] = 0;//TXDnEID0
    buf[4] = data.length + 4;//TXDnDLC
    buf[5] = data.length + 4;
    buf[6] = data.id;
    buf[7] = cmdWord;
    buf[8] = cmdWord >> 8;

    memcpy(buf + 9, data.dataBuf, data.length);

    int fastRes = spi.FastWriteTxBuf(0, buf, data.length + 5 + 4);
    if(fastRes < 0){
        return -1;
    }
    int writeRes = spi.WriteByte(TXB0DLC, data.length + 4);
    if(writeRes < 0){
        return -1;
    }
    int writeOneRes =spi.WriteOneByte(TXB0RTS | 0x80);
    if(writeOneRes < 0){
        return -1;
    }
    return 1;
}

CanDataType MCP2515::ReadBufResolve(const uint8_t* buf)
{
    uint16_t id = ((buf[0] << 3) & 0x7f8) | ((buf[1] >> 5) & 0x07);

    struct CanDataType temp;
    memcpy(&temp, buf + 5, 8);
    if((temp.cmdWord & 0xf000) == 0x8000)   ///< sReceive response
    {
        temp.dir = false;
        temp.cmdWord = temp.cmdWord & 0x0fff;
    } else   /// <Receive request
    {
        temp.dir = true;
    }
    temp.length = temp.length - 4; ///< 仅保留数据部分

/*    if(!temp.dir)
    {
        temp.cmdWord = temp.cmdWord & 0x7fff;
    }*/
    return temp;

}

bool MCP2515::CanDataReadOnce(CanDataType& dataBuf)
{
    uint8_t buf[13];
    uint8_t status = spi.ReadByte(CANINTF);

    if(status & 0x01)
    {
        bzero(buf, 13);
        spi.FastReadRxBuf(0, buf);

        if((buf[1] & 0x1f) == 0)
        {
//            LOGD("buf[1] & ox1f == 0");
            dataBuf = ReadBufResolve(buf);
//            canDataType.flag = true;
        }
    } else if(status & 0x02)
    {
        bzero(buf, 13);
        spi.FastReadRxBuf(2, buf);
        if((buf[1] & 0x1f) == 0)
        {
//            LOGD("buf[1] & ox1f == 0");
            dataBuf = ReadBufResolve(buf);
//            canDataType.flag = true;
        }
    } else {
        return false;
    }

    return true;
}